#include <HkCameraHandler.h>
#include "iostream"
HkCameraHandler::HkCameraHandler() : g_bExit(false)
{
    memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));

}

HkCameraHandler::~HkCameraHandler()
{
//      //printf("HKcamera closing...\n");
      close();
}

int HkCameraHandler::start()
{
    if(g_bExit){
        return -2;
    }

    // INIT the camera handler
    int ret = init();

    //set the camera param

    if (ret != MV_OK)
    {
        std::cout <<" HKcamera init fail! "<<std::endl;
        close();
        return -1;
    }
    std::cout <<" HKcamera setExpouse ok! "<<std::endl;
    std::cout << " HkCamera open ok"<<std::endl;
    g_bExit = true;
    return 0;
}

int HkCameraHandler::init()
{

    // 枚举设备
    // enum device
    int nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
    if (MV_OK != nRet)
    {
        //printf("MV_CC_EnumDevices fail! nRet [%x]\n", nRet);
        return -1;
    }
    if (stDeviceList.nDeviceNum > 0)
    {
        for (int i = 0; i < stDeviceList.nDeviceNum; i++)
        {
            //printf("[device %d] Find!\n", i);
            MV_CC_DEVICE_INFO *pDeviceInfo = stDeviceList.pDeviceInfo[i];
            if (NULL == pDeviceInfo)
            {
                break;
            }
            //PrintDeviceInfo(pDeviceInfo);
        }
    }
    else
    {
        //printf("Find No Devices!\n");
        return -2;
    }

    if (0 >= stDeviceList.nDeviceNum)
    {
        //printf("Intput error!\n");
        return -3;
    }

    // 选择设备并创建句柄
    // select device and create handle
    nRet = MV_CC_CreateHandle(&Camerahandle, stDeviceList.pDeviceInfo[0]);
    if (MV_OK != nRet)
    {
        //printf("MV_CC_CreateHandle fail! nRet [%x]\n", nRet);
        return -4;
    }

    // 打开设备
    // open device
    nRet = MV_CC_OpenDevice(Camerahandle);
    if (MV_OK != nRet)
    {
        //printf("MV_CC_OpenDevice fail! nRet [%x]\n", nRet);
        return -5;
    }

    // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
    if (stDeviceList.pDeviceInfo[0]->nTLayerType == MV_GIGE_DEVICE)
    {
        int nPacketSize = MV_CC_GetOptimalPacketSize(Camerahandle);
        if (nPacketSize > 0)
        {
            nRet = MV_CC_SetIntValue(Camerahandle, "GevSCPSPacketSize", nPacketSize);
            if (nRet != MV_OK)
            {
                //printf("Warning: Set Packet Size fail nRet [0x%x]!\n", nRet);
            }
        }
        else
        {
            //printf("Warning: Get Packet Size fail nRet [0x%x]!\n", nPacketSize);
        }
    }

    nRet = MV_CC_SetBoolValue(Camerahandle, "AcquisitionFrameRateEnable", false);
    if (MV_OK != nRet)
    {
        //printf("set AcquisitionFrameRateEnable fail! nRet [%x]\n", nRet);
        return -6;
    }

    // 设置触发模式为on
    // set trigger mode as on
    nRet = MV_CC_SetEnumValue(Camerahandle, "TriggerMode", 1);
    if (MV_OK != nRet)
    {
        //printf("MV_CC_SetTriggerMode fail! nRet [%x]\n", nRet);
        return -7;
    }

    // 设置触发源
    // set trigger source
    nRet = MV_CC_SetEnumValue(Camerahandle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE);
    if (MV_OK != nRet)
    {
        //printf("MV_CC_SetTriggerSource fail! nRet [%x]\n", nRet);
        return -8;
    }

    // 开始取流
    // start grab image
    nRet = MV_CC_StartGrabbing(Camerahandle);
    if (MV_OK != nRet)
    {
        //printf("MV_CC_StartGrabbing fail! nRet [%x]\n", nRet);
        return -9;
    }

}

int HkCameraHandler::TrrigerOnce(ImageType type)
{

    int flag;
    if(type == MONO){
        flag = CV_8UC1;
    }else if(type == COLOR8){
        flag = CV_8UC3;
    }

    int nRet = MV_CC_SetCommandValue(Camerahandle, "TriggerSoftware");
    if (MV_OK != nRet)
    {
        //printf("failed in TriggerSoftware[%x]\n", nRet);
        std::cout << "failed in TriggerSoftware"<<std::endl;
        return -1;
    }


    ReadBuffer(Camerahandle,tempImg,type);
    return 0;
   
}

int HkCameraHandler::getImageData(cv::Mat& outImage)
{
//    tempImg.release();
    outImage = tempImg;
    if( outImage.empty()){
        return -1;
    }
    return 0;
}

int HkCameraHandler::setExpouse(double val)
{
    MV_CC_SetExposureAutoMode(Camerahandle, 0);
    float fExposureTime = static_cast<float>(val);
    int nRet = MV_CC_SetFloatValue(Camerahandle, "ExposureTime", fExposureTime);
    return nRet;
}

int HkCameraHandler::close()
{

    int nRet = 0;
    if( g_bExit== true){
        nRet = MV_CC_CloseDevice(Camerahandle);
        if (MV_OK != nRet)
        {
            //printf("MV_CC_CloseDevice fail! nRet [%x]\n", nRet);
            nRet = -1;
        }

        // 销毁句柄
        nRet = MV_CC_DestroyHandle(Camerahandle);
        if (MV_OK != nRet)
        {
            //printf("MV_CC_DestroyHandle fail! nRet [%x]\n", nRet);
            nRet =  -2;
        }
        //printf("Camera close ok!\n");

    }else{
        //printf("Camera non-connect !\n");
        nRet = -3;
    }

    g_bExit = false;
    return nRet;
}


int HkCameraHandler::ReadBuffer(void *Camerahandle, Mat &image,ImageType color_flag)
{
    image.release();

    unsigned int nRecvBufSize = 0;
    MVCC_INTVALUE stParam;
    memset(&stParam, 0, sizeof(MVCC_INTVALUE));
    int temp = MV_CC_GetIntValue(Camerahandle, "PayloadSize", &stParam);
    if (temp != 0)
    {
        return -1;
    }

    nRecvBufSize = stParam.nCurValue;
    this->m_pBufForDriver = (unsigned char *)malloc(nRecvBufSize);
    MV_FRAME_OUT_INFO_EX stImageInfo = {0};
    int tempValue= MV_CC_GetOneFrameTimeout(Camerahandle, this->m_pBufForDriver, nRecvBufSize, &stImageInfo, 100);
    if(tempValue!=0)
    {
        return -2;
    }





    switch (color_flag) {
        case MONO:

            image = Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC1,m_pBufForDriver).clone();

            break;
        case COLOR8:
            uint32_t m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
            unsigned char* m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage);
            MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};
            memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
            stConvertParam.nWidth = stImageInfo.nWidth;                 //ch:图像宽 | en:image width
            stConvertParam.nHeight = stImageInfo.nHeight;               //ch:图像高 | en:image height
            stConvertParam.pSrcData = m_pBufForDriver;                  //ch:输入数据缓存 | en:input data buffer
            stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;         //ch:输入数据大小 | en:input data size
            stConvertParam.enSrcPixelType = stImageInfo.enPixelType;    //ch:输入像素格式 | en:input pixel format
            stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed; //ch:输出像素格式 | en:output pixel format  适用于OPENCV的图像格式
    //        stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed; //ch:输出像素格式 | en:output pixel format
            stConvertParam.pDstBuffer = m_pBufForSaveImage;                    //ch:输出数据缓存 | en:output data buffer
            stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage;            //ch:输出缓存大小 | en:output buffer size
            MV_CC_ConvertPixelType(Camerahandle, &stConvertParam);
            image = Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC3,m_pBufForSaveImage).clone();

            if(m_pBufForSaveImage != nullptr){
                free(m_pBufForSaveImage);
            }

    }

    if(m_pBufForDriver != nullptr){
        free(m_pBufForDriver);
    }




    //DBGprint("get ReadBuffer \n");
    return 0;
}
